--- title: "2305. Fair Distribution of Cookies" created: 2025-12-22 --- # 2305. Fair Distribution of Cookies ## 题目 [**2305. Fair Distribution of Cookies**](https://leetcode.com/problems/fair-distribution-of-cookies/) ![[image-b7623480.png]] ## 思路分析 思路和前面一样 可以二分出cookie 但问题是 它现在不是拿连续的了 而是可以随意组合 这意味着需要dfs去枚举所有可能 数据范围2-8是可行的 先二分猜一个答案再dfs也行 直接dfs也行 ## 代码实现 ```java class Solution { static final int INF = 0x3f3f3f3f; private boolean check(int[] cookies,int k,int mid){ int[] children = new int[k]; return dfs(cookies,cookies.length-1,children,mid); } private boolean dfs(int[] cookies,int idx,int[] children,int mid){ if(idx<0) return true; int cookie = cookies[idx]; for(int i=0;imid) continue; if(i>0 && children[i]==children[i-1]) continue; if(children[i]==0){ children[i]+=cookie; if(dfs(cookies,idx-1,children,mid)) return true; children[i]-=cookie; return false; } children[i]+=cookie; if(dfs(cookies,idx-1,children,mid)) return true; children[i]-=cookie; } return false; } public int distributeCookies(int[] cookies, int k) { int sumv=0,maxv=-INF; for(int cookie:cookies){ maxv = Math.max(cookie,maxv); sumv+=cookie; } Arrays.sort(cookies); int l=maxv,r=sumv; while(l>1; if(check(cookies,k,mid)){ r=mid; }else{ l=mid+1; } } return r; } } ``` ```java import java.util.Arrays; class Solution { public int distributeCookies(int[] cookies, int k) { int sum = 0; for (int c : cookies) sum += c; // 排序优化:从大到小拿饼干,如果大的放不进,剪枝会更快 Arrays.sort(cookies); // 倒序处理,虽然Java Arrays没有直接降序,我们可以在dfs里倒着遍历 // 二分范围: // 下界 l:至少得装下最大的那一袋饼干(因为不能拆分) // 上界 r:一个人拿走所有饼干 int l = cookies[cookies.length - 1]; int r = sum; while (l < r) { int mid = l + r >> 1; // check: 尝试用 k 个孩子,每个孩子上限 mid,能不能分完所有 cookies if (check(cookies, k, mid)) { r = mid; } else { l = mid + 1; } } return r; } // 检查函数:能否将所有饼干分给 k 个孩子,且每个人不超过 limit private boolean check(int[] cookies, int k, int limit) { int[] children = new int[k]; // 记录每个孩子当前拿了多少 // 从最后一个饼干(最大的)开始分,容易触发剪枝 return backtrack(cookies, cookies.length - 1, children, limit); } // 回溯具体逻辑 private boolean backtrack(int[] cookies, int idx, int[] children, int limit) { // Base Case: 所有的饼干都分完了,说明这个 limit 是可行的 if (idx < 0) return true; int cookie = cookies[idx]; // 当前要分的饼干 // 尝试把这袋饼干给 k 个孩子中的某一个 for (int i = 0; i < children.length; i++) { // 剪枝1:如果给在这个孩子会导致超标,就跳过 if (children[i] + cookie > limit) continue; // 剪枝2(极其重要):如果当前孩子和前一个孩子拿的饼干一样多, // 那么给这一袋饼干给谁都是一样的,前面那个失败了,这个肯定也失败,跳过。 // 或者是:如果当前孩子是空的,且把饼干给他后最终失败了, // 那么给后面任何一个空着的孩子都会失败(因为大家都是空的,等价的)。 if (i > 0 && children[i] == children[i-1]) continue; // 实际上对于本题二分check,最强剪枝是:如果当前 bucket 为 0 且递归失败,直接 return false // 但为了逻辑简单,用上面的去重逻辑也可以,或者用下面的写法: if (children[i] == 0) { // 如果这是一个空桶,尝试放入 children[i] += cookie; if (backtrack(cookies, idx - 1, children, limit)) return true; children[i] -= cookie; // 关键点:如果给第一个空桶都失败了,给后面的空桶肯定也失败,直接return false return false; } // 正常回溯逻辑 children[i] += cookie; if (backtrack(cookies, idx - 1, children, limit)) return true; children[i] -= cookie; // 回溯 } return false; } } ``` ![[image-f97327a6.png]] 既然 `N` 只有 8,其实我们根本**不需要二分**。二分是在“猜”答案,然后去验证。 既然验证过程本身就是指数级的,我们不如直接**暴力枚举**所有分发方案,在这个过程中维护一个全局最小值。 这种写法代码更短,逻辑更直观。 #### 核心思路 1. 维护一个全局变量 `ans` 记录最小的不公平值。 2. `dfs(index)`: 决定第 `index` 袋饼干给哪个孩子。 ``` class Solution { static final int INF = 0x3f3f3f3f; int ans = INF; public int distributeCookies(int[] cookies, int k) { int[] children = new int[k]; dfs(cookies,0,children,k); return ans; } private void dfs(int[] cookies,int idx,int[] children,int k){ if(idx == cookies.length){ int maxCookie=0; for(int c:children) maxCookie=Math.max(maxCookie,c); ans = Math.min(ans,maxCookie); return; } int cookie = cookies[idx]; for(int i=0;i=ans) continue; children[i]+=cookie; dfs(cookies,idx+1,children,k); children[i]-=cookie; } } } ``` 3. **剪枝**:如果在分发过程中,某个孩子手里的饼干已经超过了当前的 `ans`,那就没必要继续分了(因为结果肯定比 `ans` 差)。 ```java class Solution { int ans = Integer.MAX_VALUE; public int distributeCookies(int[] cookies, int k) { // 每个人当前手里的饼干总数 int[] children = new int[k]; dfs(cookies, 0, children, k); return ans; } private void dfs(int[] cookies, int idx, int[] children, int k) { // 如果所有饼干都分完了 if (idx == cookies.length) { // 算出当前方案的不公平程度(所有孩子里的最大值) int maxCookie = 0; for (int c : children) maxCookie = Math.max(maxCookie, c); // 更新全局最小 ans = Math.min(ans, maxCookie); return; } int cookie = cookies[idx]; // 尝试把这袋饼干给 k 个孩子中的每一个 for (int i = 0; i < k; i++) { // 剪枝1:如果当前孩子拿完这袋饼干就已经超过了已知的最优解 ans // 那这个方案肯定不是最优解,直接剪掉 if (children[i] + cookie >= ans) continue; // 剪枝2:空桶优化 // 如果当前桶是空的,且把饼干给他之后,后面的递归没能找到比 ans 更优的解 // 那么给后面其他空桶也是没用的(因为空桶是等价的),直接 break if (children[i] == 0) { children[i] += cookie; dfs(cookies, idx + 1, children, k); children[i] -= cookie; break; // 关键:不需要尝试下一个空桶了 } // 正常回溯 children[i] += cookie; dfs(cookies, idx + 1, children, k); children[i] -= cookie; } } } ``` ![[image-fda5b3c1.png]] ## 同类题型 ## 视频讲解